package com.library.config;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 * 负责JWT令牌的生成、解析和验证
 * JWT (JSON Web Token) 是一种无状态的认证方式，不需要在服务器端存储session
 */
@Component
public class JwtUtil {
    /**
     * JWT签名密钥
     * 从配置文件application.yml中读取
     * 用于签名和验证JWT令牌，生产环境应该使用更复杂的密钥
     */
    @Value("${jwt.secret}")
    private String secret;

    /**
     * JWT令牌过期时间（毫秒）
     * 从配置文件application.yml中读取
     * 默认24小时（86400000毫秒）
     */
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 获取JWT签名密钥
     * 使用HMAC-SHA算法生成签名密钥
     * 
     * @return SecretKey 签名密钥
     */
    private SecretKey getSigningKey() {
        return Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 生成JWT令牌
     * 将用户信息（ID、用户名、角色）编码到JWT中
     * 
     * @param userId 用户ID
     * @param username 用户名
     * @param role 用户角色
     * @return String JWT令牌字符串
     */
    public String generateToken(Long userId, String username, String role) {
        // 创建claims（声明），存储用户信息
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", userId);
        claims.put("username", username);
        claims.put("role", role);
        
        // 构建JWT令牌
        return Jwts.builder()
                .claims(claims)  // 设置声明
                .subject(username)  // 设置主题（通常是用户名）
                .issuedAt(new Date())  // 设置签发时间
                .expiration(new Date(System.currentTimeMillis() + expiration))  // 设置过期时间
                .signWith(getSigningKey())  // 使用密钥签名
                .compact();  // 生成最终的JWT字符串
    }

    /**
     * 从JWT令牌中提取声明（claims）
     * 包含用户信息和令牌元数据
     * 
     * @param token JWT令牌字符串
     * @return Claims 包含用户信息的声明对象
     * @throws Exception 当令牌无效、过期或签名错误时抛出异常
     */
    public Claims extractClaims(String token) {
        return Jwts.parser()
                .verifyWith(getSigningKey())  // 使用密钥验证签名
                .build()
                .parseSignedClaims(token)  // 解析并验证令牌
                .getPayload();  // 获取payload（包含claims）
    }

    /**
     * 检查JWT令牌是否已过期
     * 
     * @param token JWT令牌字符串
     * @return boolean true表示已过期，false表示未过期
     */
    public boolean isTokenExpired(String token) {
        try {
            Claims claims = extractClaims(token);
            // 比较过期时间和当前时间
            return claims.getExpiration().before(new Date());
        } catch (Exception e) {
            // 如果解析失败（令牌无效），视为已过期
            return true;
        }
    }

    /**
     * 验证JWT令牌是否有效
     * 检查令牌是否未过期且签名正确
     * 
     * @param token JWT令牌字符串
     * @return boolean true表示有效，false表示无效
     */
    public boolean validateToken(String token) {
        try {
            Claims claims = extractClaims(token);
            // 检查是否未过期
            return !claims.getExpiration().before(new Date());
        } catch (Exception e) {
            // 任何异常都表示令牌无效
            return false;
        }
    }
}

